package com.backend.modules.system.service.impl;

import com.backend.common.enums.UserType;
import com.backend.common.exception.BusinessException;
import com.backend.common.utils.JwtUtils;
import com.backend.common.utils.SecurityUtils;
import com.backend.modules.system.dto.DepartmentQueryDTO;
import com.backend.modules.system.dto.LoginDTO;
import com.backend.modules.system.dto.RegisterDTO;
import com.backend.modules.system.dto.UpdatePasswordDto;
import com.backend.modules.system.dto.UserQueryDTO;
import com.backend.modules.system.dto.UserUpdateDTO;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.system.entity.SysDepartment;
import com.backend.modules.system.repository.SysUserRepository;
import com.backend.modules.system.service.SysUserService;
import com.backend.modules.system.service.TokenService;
import com.backend.modules.system.service.SysDepartmentService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class SysUserServiceImpl implements SysUserService {

    private final SysUserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final TokenService tokenService;
    private final SysDepartmentService departmentService;

    @Override
    public String login(LoginDTO loginDTO) {
        SysUser user = userRepository.findByUsername(loginDTO.getUsername())
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        if (!passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) {
            throw new BusinessException("密码错误");
        }
        
        if (!user.getStatus()) {
            throw new BusinessException("账号已被禁用");
        }
        
        return tokenService.generateToken(user.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(RegisterDTO registerDTO) {
        // 检查用户名是否存在
        if (userRepository.existsByUsername(registerDTO.getUsername())) {
            throw new BusinessException("用户名已存在");
        }
        
        // 校验用户类型
        UserType userType = UserType.valueOf(registerDTO.getUserType());
        if (userType == null) {
            throw new BusinessException("无效的用户类型");
        }
        
        // 只有管理员可以创建管理员账号
        if (UserType.ADMIN.equals(userType)) {
            throw new BusinessException("无权创建管理员账号");
        }
        
        SysUser user = new SysUser();
        user.setUsername(registerDTO.getUsername());
        user.setPassword(passwordEncoder.encode(registerDTO.getPassword()));
        user.setRealName(registerDTO.getRealName());
        user.setPhone(registerDTO.getPhone());
        user.setEmail(registerDTO.getEmail());
        user.setUserType(registerDTO.getUserType());
        
        userRepository.save(user);
    }

    @Override
    public SysUser getCurrentUser() {
        Long userId = SecurityUtils.getCurrentUserId();
        return userRepository.findById(userId)
                .orElseThrow(() -> new BusinessException("用户不存在"));
    }

    @Override
    public SysUser getById(Long id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new BusinessException("用户不存在"));
    }

    @Override
    public Page<SysUser> page(UserQueryDTO query, Pageable pageable) {
        Specification<SysUser> spec = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 用户名
            if (StringUtils.hasText(query.getUsername())) {
                predicates.add(criteriaBuilder.like(root.get("username"), "%" + query.getUsername() + "%"));
            }
            
            // 真实姓名
            if (StringUtils.hasText(query.getRealName())) {
                predicates.add(criteriaBuilder.like(root.get("realName"), "%" + query.getRealName() + "%"));
            }
            
            // 手机号
            if (StringUtils.hasText(query.getPhone())) {
                predicates.add(criteriaBuilder.like(root.get("phone"), "%" + query.getPhone() + "%"));
            }
            
            // 用户类型
            if (query.getUserType() != null) {
                predicates.add(criteriaBuilder.equal(root.get("userType"), query.getUserType()));
            }
            
            // 状态
            if (query.getStatus() != null) {
                predicates.add(criteriaBuilder.equal(root.get("status"), query.getStatus()));
            }
            
            // 部门查询
            if (query.getDepartmentId() != null) {
                if (Boolean.TRUE.equals(query.getIncludeChildren())) {
                    // 查询包含子部门的用户
                    List<Long> departmentIds = getDepartmentIdsWithChildren(query.getDepartmentId());
                    predicates.add(root.get("department").get("id").in(departmentIds));
                } else {
                    // 只查询指定部门的用户
                    predicates.add(criteriaBuilder.equal(root.get("department").get("id"), query.getDepartmentId()));
                }
            }
            
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        return userRepository.findAll(spec, pageable);
    }

    /**
     * 获取部门及其所有子部门的ID列表
     */
    private List<Long> getDepartmentIdsWithChildren(Long departmentId) {
        List<Long> departmentIds = new ArrayList<>();
        departmentIds.add(departmentId);
        
        // 获取部门树
        SysDepartment department = departmentService.getById(departmentId);
        addChildDepartmentIds(department, departmentIds);
        
        return departmentIds;
    }

    /**
     * 递归添加子部门ID
     */
    private void addChildDepartmentIds(SysDepartment department, List<Long> departmentIds) {
        List<SysDepartment> children = departmentService.list(DepartmentQueryDTO.builder()
                .parentId(department.getId())
                .build());
        
        for (SysDepartment child : children) {
            departmentIds.add(child.getId());
            addChildDepartmentIds(child, departmentIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Boolean status) {
        SysUser user = getById(id);
        
        // 不能修改自己的状态
        if (user.getId().equals(SecurityUtils.getCurrentUserId())) {
            throw new BusinessException("不能修改自己的状态");
        }
        
        // 不能修改管理员的状态
        if (UserType.ADMIN.getValue().equals(user.getUserType())) {
            throw new BusinessException("不能修改管理员的状态");
        }
        
        user.setStatus(status);
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Long id) {
        SysUser user = getById(id);
        
        // 不能重置管理员的密码
        if (UserType.ADMIN.getValue().equals(user.getUserType())) {
            throw new BusinessException("不能重置管理员的密码");
        }
        
        // 重置为默认密码：123456
        user.setPassword(passwordEncoder.encode("123456"));
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, UserUpdateDTO dto) {
        SysUser user = getById(id);
        
        // 不能修改管理员信息
        if (UserType.ADMIN.getValue().equals(user.getUserType())) {
            throw new BusinessException("不能修改管理员信息");
        }
        
        // 校验部门是否存在
        SysDepartment department = departmentService.getById(dto.getDepartmentId());
        
        user.setRealName(dto.getRealName());
        user.setPhone(dto.getPhone());
        user.setEmail(dto.getEmail());
        user.setDepartment(department);
        user.setAvatar(dto.getAvatar());
        
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCurrentUser(UserUpdateDTO dto) {
        SysUser user = getCurrentUser();
        

        user.setRealName(dto.getRealName());
        user.setPhone(dto.getPhone());
        user.setEmail(dto.getEmail());
        user.setAvatar(dto.getAvatar());
        
        userRepository.save(user);
    }

    @Override
    public void updatePassword(UpdatePasswordDto dto) {
         SysUser user = getCurrentUser();
         if (!passwordEncoder.matches(dto.getOldPassword(), user.getPassword())) {
             throw new BusinessException("旧密码错误");
         }
         user.setPassword(passwordEncoder.encode(dto.getNewPassword()));
         userRepository.save(user);
    }
} 